package com.xinyin.aiqinhaiback.modbus;

import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.locator.BaseLocator;
import com.xinyin.aiqinhaiback.Utils.ModbusAddressUtil;
import com.xinyin.aiqinhaiback.common.Enum.ResultEnum;
import com.xinyin.aiqinhaiback.exception.MyException;

import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * modbus通讯工具类,采用modbus4j实现
 *
 */
public class Modbus4jUtils {
    /**
     * 工厂。
     */
    static ModbusFactory modbusFactory;
    static {
        if (modbusFactory == null) {
            modbusFactory = new ModbusFactory();
        }
    }

   private  String ip="211.154.22.175";
    private  String port="10038";

    public Modbus4jUtils(String ip,String port) {
        this.ip=ip;
        this.port=port;
    }


    /**
     * 获取master
     *
     * @return
     * @throws ModbusInitException
     */
    public  ModbusMaster getMaster() throws ModbusInitException {
        IpParameters params = new IpParameters();
        params.setHost(this.ip);
        params.setPort(Integer.valueOf(this.port));

        //
        // modbusFactory.createRtuMaster(wapper); //RTU 协议
        // modbusFactory.createUdpMaster(params);//UDP 协议
        // modbusFactory.createAsciiMaster(wrapper);//ASCII 协议
        ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议
        master.setTimeout(10000);
        master.init();

        return master;
    }

    /**
     * 读取[01 Coil Status 0x]类型 开关数据
     *
     * @param slaveId
     *            slaveId
     * @param offset
     *            位置
     * @return 读取值
     * @throws ModbusTransportException
     *             异常
     * @throws ErrorResponseException
     *             异常
     * @throws ModbusInitException
     *             异常
     */
    public  Boolean readCoilStatus(int slaveId, int offset)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 01 Coil Status
        BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
        Boolean value = getMaster().getValue(loc);
        return value;
    }

    /**
     * 读取[02 Input Status 1x]类型 开关数据
     *
     * @param slaveId
     * @param offset
     * @return
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     * @throws ModbusInitException
     */
    public  Boolean readInputStatus(int slaveId, int offset)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 02 Input Status
        BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
        Boolean value = getMaster().getValue(loc);
        return value;
    }

    /**
     * 读取[03 Holding Register类型 2x]模拟量数据
     *
     * @param slaveId
     *            slave Id
     * @param offset
     *            位置
     * @param dataType
     *            数据类型,来自com.serotonin.modbus4j.code.DataType
     * @return
     * @throws ModbusTransportException
     *             异常
     * @throws ErrorResponseException
     *             异常
     * @throws ModbusInitException
     *             异常
     */
    public  Number readHoldingRegister(int slaveId, int offset, int dataType)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 03 Holding Register类型数据读取
        BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
        Number value = getMaster().getValue(loc);
        return value;
    }

    /**
     * 读取[04 Input Registers 3x]类型 模拟量数据
     *
     * @param slaveId
     *            slaveId
     * @param offset
     *            位置
     * @param dataType
     *            数据类型,来自com.serotonin.modbus4j.code.DataType
     * @return 返回结果
     * @throws ModbusTransportException
     *             异常
     * @throws ErrorResponseException
     *             异常
     * @throws ModbusInitException
     *             异常
     */
    public  Number readInputRegisters(int slaveId, int offset, int dataType)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 04 Input Registers类型数据读取
        BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
        Number value = getMaster().getValue(loc);
        return value;
    }

    /**
     * 批量读取使用方法
     *
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     * @throws ModbusInitException
     */


    public   BatchResults<Integer> batchRead(Set<Integer> list) throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        BatchResults<Integer> results;

        AtomicInteger currentPort = new AtomicInteger(0);
        try {
            BatchRead<Integer> batch = new BatchRead<Integer>();

            for(Integer port :list){
                currentPort.set(port);
                if (ModbusAddressUtil.getFunctionCode(port)==1){
                    batch.addLocator(port, BaseLocator.coilStatus(1, ModbusAddressUtil.getOffset(port)));
                }

                if (ModbusAddressUtil.getFunctionCode(port)==2){
                    batch.addLocator(port, BaseLocator.inputStatus(1,  ModbusAddressUtil.getOffset(port)));
                }

                if (ModbusAddressUtil.getFunctionCode(port)==3){
                    batch.addLocator(port, BaseLocator.holdingRegister(1, ModbusAddressUtil.getOffset(port), DataType.FOUR_BYTE_FLOAT));
                }

                if (ModbusAddressUtil.getFunctionCode(port)==4){
                    batch.addLocator(port, BaseLocator.inputRegister(1, ModbusAddressUtil.getOffset(port)-1,DataType.FOUR_BYTE_FLOAT_SWAPPED));
                }
            }

            ModbusMaster master = getMaster();
            batch.setContiguousRequests(false);
            results = master.send(batch);
            System.out.println(ip+results);
        }catch (Exception e) {
            System.err.println("Modbus 错误: " + e.getMessage()+ip+":"+port+":"+currentPort.get()+getMaster());
            // 进一步处理异常
            throw new MyException(ResultEnum.COMMON_FAILED);
        }finally {
           getMaster().destroy();
        }
        return results;
    }



    public Object getData(Integer port) throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        Object obj=new Object();
        try {


        if (ModbusAddressUtil.getFunctionCode(port)==1){
            obj=readInputStatus(1, ModbusAddressUtil.getOffset(port));
        }

        if (ModbusAddressUtil.getFunctionCode(port)==2){
            obj=readInputStatus(1,  ModbusAddressUtil.getOffset(port));
        }

        if (ModbusAddressUtil.getFunctionCode(port)==3){
            obj=readHoldingRegister(1,  ModbusAddressUtil.getOffset(port), DataType.FOUR_BYTE_FLOAT);
        }

        if (ModbusAddressUtil.getFunctionCode(port)==4){
            obj= readInputRegisters(1,  ModbusAddressUtil.getOffset(port), DataType.FOUR_BYTE_FLOAT_SWAPPED);//
        }
        }catch (Exception e){
            System.out.println(port+"error"+e.getMessage());
        }
            return obj;
    }
        /**
     * 测试
     *
     * @param args
     */
    public  static void main(String[] args) {
        try {
//            DecimalFormat df = new DecimalFormat("0.00");
//            String formatted = df.format( true);
//            System.out.println(formatted);
            Modbus4jUtils modbus4jUtils=new Modbus4jUtils("127.0.0.1","502");


            BatchRead<Integer> batch = new BatchRead<>();

            for (int i = 0; i <= 10; i++) {
                batch.addLocator(
//                            i, BaseLocator.inputRegister(1, i - 1, DataType.TWO_BYTE_INT_UNSIGNED)
                            i, BaseLocator.holdingRegister(1,  i, DataType.FOUR_BYTE_FLOAT)
                    );
            }
//            batch.addLocator(
//                    22, BaseLocator.inputRegister(1, 22, DataType.TWO_BYTE_INT_UNSIGNED)
//            );
            batch.setContiguousRequests(true);

            BatchResults<Integer> results = modbus4jUtils.getMaster().send(batch);

//             = master.send(batch);

            System.out.println(results);

            // 01测试
//            Boolean v011 = readCoilStatus(1, 0);
          //  Boolean v012 = readCoilStatus(1, 1);
//            Boolean v013 = modbus4jUtils.readCoilStatus(1, 646-1);
//           System.out.println("v011:" + v013);
//            System.out.println("v012:" + v012);
//            System.out.println("v013:" + v013);
            // 02测试
//            Boolean v023 = modbus4jUtils.readInputStatus(1, 78);
//           System.out.println("v021:" + v023);
//            System.out.println("v022:" + v022);
//            System.out.println("v023:" + v023);
//
//            // 03测试
//            Number v031 = modbus4jUtils.readHoldingRegister(1, 39, DataType.FOUR_BYTE_FLOAT);// 注意,float

//            for (int i = 1; i <= i + 100; i ++) {
//                Number v032 = modbus4jUtils.readInputRegisters(1, i,DataType.TWO_BYTE_INT_UNSIGNED);// 同上
//                System.out.println(i);
//                System.out.println(v032);
//
//            }

//            System.out.println("v032:" + v032);

            // 04测试
          //  System.out.println(modbus4jUtils.readInputRegisters(1, 238, DataType.FOUR_BYTE_FLOAT_SWAPPED));
            // 批量读取
          //  batchRead();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
